#include "logProc.h"
#ifdef __linux__
#include <sys/prctl.h>
#endif
static char *dataLogPath="data";

//设置事件的存储目录
void setDataLogPath(char *path)
{
    if(path && path!="")
    {
        dataLogPath=path;
        mkdir(dataLogPath,666);
    }
}
char * getDataLogPath()
{
    if(access(dataLogPath,F_OK)!=0)
    {
        mkdir(dataLogPath,666);
    }
    return dataLogPath;
}
void setThreadName(char *name)
{
#ifdef __linux__
    prctl(PR_SET_NAME,name);
#endif
}

/**
 * 检查某类文件,比如eventLog-2018-10-11.log，eventLog-2018-10-12.log
   如果文件超过一定个数，则删除最早创建的
@param  head-文件名的头部
@param count-文件个数
**/
void checkAndClearLog(char *head,int count)
{
    DIR *dfd;
    char name[100];
    char pathname[100]={0};
    struct dirent *dp;
    sprintf(pathname,"%s",dataLogPath);
    int fileCount=0;
    char fileList[100][100];
    time_t timeList[100];
    memset(fileList,0,sizeof(fileList));
    memset(timeList,0,sizeof(timeList));

    if ((dfd = opendir(pathname)) == NULL)
    {
        //AppLogOut("dir_order: can't open %s\n %s", pathname,strerror(errno));
        return ;
    }

    while ((dp = readdir(dfd)) != NULL)
    {
        if (strncmp(dp->d_name, ".", 1) == 0)
            continue; /* ????????????????????*/
        if (strlen(pathname) + strlen(dp->d_name) + 2 > sizeof(name))
        {
            //printf("dir_order: name %s %s too long\n", pathname, dp->d_name);
            continue;
        }
        if(strncmp(head,dp->d_name,strlen(head))==0)
        {
            struct stat fileStat;
            sprintf(name,"%s/%s",pathname,dp->d_name);
            if(fileCount>=100)
                break;
            if(stat(name,&fileStat)>=0)
            {
                sprintf(fileList[fileCount],"%s",dp->d_name);
                timeList[fileCount]=fileStat.st_ctime;
                fileCount++;
            }
        }
    }
    int deleteCount=fileCount-count;//计算待删除文件数
    if(deleteCount>0)
    {
        int i,j;
        for(j=0;j<deleteCount;j++)
        {
            time_t min=time(NULL);
            int index=0;
            for(i=0;i<fileCount;i++)
            {
                if(timeList[i]<min)
                {
                    min=timeList[i];
                    index=i;
                }
            }
            sprintf(name,"%s/%s",pathname,fileList[index]);
            remove(name);
            timeList[index]=time(NULL);
        }
    }

    closedir(dfd);
}

char *getTimeStr(char *buf,time_t t)
{
    struct tm local;
    localtime_r(&t,&local);
    snprintf(buf,20,"%04d-%02d-%02d %02d:%02d:%02d",
             local.tm_year+1900,
             local.tm_mon+1,
             local.tm_mday,
             local.tm_hour,
             local.tm_min,
             local.tm_sec);
    return buf;
}

char *getDateStr(char *buf,time_t t)
{
    struct tm local;
    localtime_r(&t,&local);
    snprintf(buf,20,"%04d-%02d-%02d",
             local.tm_year+1900,
             local.tm_mon+1,
             local.tm_mday
             );
    return buf;
}

/**
 * @brief
 *
 * @param logfile
 * @param header log数据的头
 * @param data log数据
 * @param maxsize 指的是log文件的最大长度
 */
void writeLog(char *logfile,char *header,char *data,int maxsize)
{
    char bak[100];
    memset(bak,0,100);
    if(strlen(logfile)>=100)
    {
        DebugLogOut("%s name too long",logfile);
        return;
    }
    FILE *file;
    sprintf(bak,"%s%s",logfile,".bak");
    file=fopen(logfile,"a+");
    if(file)
    {
        if(header)
            fputs(header,file);
        fputs(data,file);
        fputs("\r\n",file);

        // 取当前日志文件的长度
        long loffset = 0;
        if( fseek( file, 0, SEEK_END ) == 0 )
        {
            loffset = ftell( file );
        }

        fclose( file );


        // 判断日志文件是否超长，如超长，将其命名为bak文件
        if( loffset > maxsize )
        {
            //定期清理系统缓存,防止段错误
            system("echo 1>/proc/sys/vm/drop_caches");
            if( remove( bak) == -1 )
            {
                fputs( header, stderr );
                fputs( "删除备份日志文件失败!\x0D\x0A", stderr );
            }

            if( rename( logfile,bak) == -1 )
            {
                fputs( header, stderr );
                fputs( "备份日志文件失败!\x0D\x0A", stderr );
                if( remove( logfile ) == -1 )
                {
                    fputs( header, stderr );
                    fputs( "删除日志文件失败!\x0D\x0A", stderr );
                }
            }
            else
            {
                fputs( header, stderr );
                fputs( "备份日志文件成功!\x0D\x0A", stderr );
            }
        }
    }
    else
    {
        fputs( "failed to open log file\x0D\x0A", stderr );
    }
}

//*****************************************************************
// 函数名称：Log_Prn
// 功能描述：打印日志函数：
// 输入参数：logfile      -  日志文件名，为NULL时，屏幕打印
//           fmt          -  打印的字符串
//           ap           -  字符串格式
// 输出参数：
// 返    回：
// 其他：
//*****************************************************************
void Log_Prn( const char *fmt, va_list ap, char *logfile ,int maxSize)
{


    char buf[MAXLINELEN+50] = { 0 };
    if(strlen(fmt)>MAXLINELEN)
    {
        return;
    }
    char szLine[50] = {0, };
    struct timeb timebuffer;
    struct tm local;
    time_t t;
    time(&t);
    ftime(&timebuffer);
    char timeline[50]={0};
    localtime_r(&t,&local);
    snprintf(timeline,20,"%04d-%02d-%02d %02d:%02d:%02d",
             local.tm_year+1900,
             local.tm_mon+1,
             local.tm_mday,
             local.tm_hour,
             local.tm_min,
             local.tm_sec);
    snprintf(szLine,25,"%.20s:%03hu ",timeline,timebuffer.millitm);

    vsprintf( buf, fmt, ap );
    buf[MAXLINELEN-1]=0;
    //printf("%s",szLine);
    //printf("%s\n",buf);

    writeLog(logfile,szLine,buf,maxSize);


}




//*****************************************************************
// 函数名称：AppLogOut
// 功能描述：记录日志文件函数：
// 输入参数：fmt          -  打印的字符串
// 输出参数：
// 返    回：
// 其他：
//*****************************************************************
void AppLogOut(const char *fmt, ...)
{
    va_list ap;
    static pthread_mutex_t gLogMutex;

    if(pthread_mutex_lock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);
        if(pthread_mutex_lock(&gLogMutex)!=0)
            return;
    }
    char name[100]={0};
    sprintf(name,"%s/app.log",getDataLogPath());

    va_start( ap, fmt );
    Log_Prn( fmt, ap, name,APP_LOG_MAX_SIZE);
    va_end( ap );
    if(pthread_mutex_unlock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);

    }

    return;
}

void AlarmLogOut(const char *fmt, ...)
{
    va_list ap;
    static pthread_mutex_t gLogMutex;

    if(pthread_mutex_lock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);
        if(pthread_mutex_lock(&gLogMutex)!=0)
            return;
    }
    char name[100]={0};
    sprintf(name,"%s/alarm.log",getDataLogPath());

    va_start( ap, fmt );
    Log_Prn( fmt, ap, name,APP_LOG_MAX_SIZE);
    va_end( ap );
    if(pthread_mutex_unlock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);

    }

    return;
}

void FaultLogOut(const char *fmt, ...)
{
    va_list ap;
    static pthread_mutex_t gLogMutex;

    if(pthread_mutex_lock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);
        if(pthread_mutex_lock(&gLogMutex)!=0)
            return;
    }
    char name[100]={0};
    sprintf(name,"%s/fault.log",getDataLogPath());

    va_start( ap, fmt );
    Log_Prn( fmt, ap, name,APP_LOG_MAX_SIZE);
    va_end( ap );
    if(pthread_mutex_unlock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);

    }

    return;
}

void RunEventLogOut(const char *fmt,...)
{
    va_list ap;
    static pthread_mutex_t gLogMutex;

    if(pthread_mutex_lock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);
        if(pthread_mutex_lock(&gLogMutex)!=0)
            return;
    }
    time_t now=time(NULL);
    char buf[100]={0};
    getDateStr(buf,now);
    char name[100]={0};
    sprintf(name,"%s/runEvent-%s.log",dataLogPath,buf);
    if(!access(name,F_OK)==0)
    {
        checkAndClearLog("runEvent",30);

    }
    va_start( ap, fmt );
    Log_Prn( fmt, ap, (char *)name,512*1024);
    va_end( ap );
    if(pthread_mutex_unlock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);

    }

}

void DealLogOut(const char *fmt, ...)
{
    va_list ap;
    static pthread_mutex_t gLogMutex;

    if(pthread_mutex_lock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);
        if(pthread_mutex_lock(&gLogMutex)!=0)
            return;
    }
    char name[100]={0};
    sprintf(name,"%s/deal.log",getDataLogPath());
    va_start( ap, fmt );
    Log_Prn( fmt, ap, name,APP_LOG_MAX_SIZE);
    va_end( ap );
    if(pthread_mutex_unlock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);

    }

    return;
}

void PropertyLogOut(const char *fmt, ...)
{
    va_list ap;
    static pthread_mutex_t gLogMutex;

    if(pthread_mutex_lock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);
        if(pthread_mutex_lock(&gLogMutex)!=0)
            return;
    }
    char name[100]={0};
    sprintf(name,"%s/property.log",getDataLogPath());
    va_start( ap, fmt );
    Log_Prn( fmt, ap, name,APP_LOG_MAX_SIZE);
    va_end( ap );
    if(pthread_mutex_unlock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);

    }

    return;
}

void MemLogOut(const char *fmt, ...)
{
    va_list ap;
    static pthread_mutex_t gLogMutex;

    if(pthread_mutex_lock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);
        if(pthread_mutex_lock(&gLogMutex)!=0)
            return;
    }
    char name[100]={0};
    sprintf(name,"%s/mem.log",getDataLogPath());
    va_start( ap, fmt );
    Log_Prn( fmt, ap, name,APP_LOG_MAX_SIZE);
    va_end( ap );
    if(pthread_mutex_unlock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);

    }

    return;
}


void DebugLogOut(const char *fmt, ...)
{
    va_list ap;
    static pthread_mutex_t gLogMutex;

    if(pthread_mutex_lock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);
        if(pthread_mutex_lock(&gLogMutex)!=0)
            return;
    }
    char name[100]={0};
    sprintf(name,"%s/debug.log",getDataLogPath());
    va_start( ap, fmt );
    Log_Prn( fmt, ap, name ,APP_LOG_MAX_SIZE);
    va_end( ap );

    if(pthread_mutex_unlock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);

    }
    return;
}

void ControlLogOut(const char *fmt, ...)
{
    static pthread_mutex_t gLogMutex;

    if(pthread_mutex_lock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);
        if(pthread_mutex_lock(&gLogMutex)!=0)
            return;
    }
    char name[100]={0};
    sprintf(name,"%s/control.log",getDataLogPath());
    va_list ap;
    va_start( ap, fmt );
    Log_Prn( fmt, ap, name ,APP_LOG_MAX_SIZE);
    va_end( ap );
    if(pthread_mutex_unlock(&gLogMutex)!=0)
    {
        pthread_mutex_init(&gLogMutex,NULL);

    }
    return;
}

